/*
 * File:   persontest.c
 * Author: ossi
 *
 * Created on 06-Nov-2011, 13:56:10
 */

#include <stdio.h>
#include <stdlib.h>
#include <CUnit/Basic.h>
#include <stdbool.h>
#include <wchar.h>
#include "relation.h"
#include "person.h"
#include "familytree.h"
#include "dynarray.h"

/*
 * CUnit Test Suite
 */

int init_suite(void) {
    ft_init();
    wchar_t* name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Testi Äöä");
    
    ft_add_person(name,new_date(1,2,2222),NULL_DATE,L'm');
    
    name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Toinen Henkilö");
    ft_add_person(name,new_date(1,2,4444),new_date(3,4,6666),L'n');
    
    name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Vielä Yksi");
    ft_add_person(name,new_date(6,2,3432),new_date(4,5,6252),L'n');
    
    return 0;
}

int clean_suite(void) {
    ft_free();
    return 0;
}

void testPer_add_child() {
    person* parent1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* parent2 = ft_get_person_by_name(L"Vielä Yksi");
    
    wchar_t* name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Lapsi 1");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2340),L'm');
    
    person* child = ft_get_person_by_name(L"Lapsi 1");
    
    relation r1, r2;
    r1.person1 = parent1;
    r1.person2 = child;
    
    r2.person1 = parent2;
    r2.person2 = child;
    
    r1.type = r2.type = REL_CHILD;
    
    _Bool result = per_add_child(parent1, parent2, child);
    
    CU_ASSERT(result);    
    CU_ASSERT(per_has_relation(parent1, &r1));
    CU_ASSERT(per_has_relation(parent2, &r2));
    CU_ASSERT(per_has_relation(child, &r1));
    CU_ASSERT(per_has_relation(child, &r2));
}

void testPer_add_child_singleparent() {
    person* parent = ft_get_person_by_name(L"Testi Äöä");
    
    person* child;
    
    wchar_t* name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Lapsi 2");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2340),L'm');
    
    child = ft_get_person_by_name(L"Lapsi 2");
    
    relation r1;
    r1.person1 = parent;
    r1.person2 = child;
    r1.type = REL_CHILD;
    
    
    _Bool result = per_add_child_singleparent(parent, child);
    CU_ASSERT(result);
    CU_ASSERT(per_has_relation(parent,&r1));
    CU_ASSERT(per_has_relation(child,&r1));
}

void testPer_compare() {
    person* person1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* person2 = ft_get_person_by_name(L"Vielä Yksi");
    int result = per_compare(person1, person2);
    CU_ASSERT(result < 0);
    result = per_compare(person2, person1);
    CU_ASSERT(result > 0);
    result = per_compare(person1, person1);
    CU_ASSERT(result == 0);    
}

void testPer_get_ancestor() {
    
    person* parent1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* parent2 = ft_get_person_by_name(L"Vielä Yksi");
    
    
    wchar_t* name = malloc(40*sizeof(wchar_t)); //lisätään vanhemmille lapsi
    wcscpy(name,L"Lapsi 3");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2340),L'm');
    
    person* child = ft_get_person_by_name(L"Lapsi 3");    
    
    _Bool result = per_add_child(parent1, parent2, child);
    CU_ASSERT(result);
   
    
    name = malloc(40*sizeof(wchar_t)); //lisätään lapsenlapsi
    wcscpy(name,L"Lapsi 4");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2340),L'm');
    
    person *child2 = ft_get_person_by_name(L"Lapsi 4");
    
    result = per_add_child_singleparent(child, child2);
    CU_ASSERT(result);
    
    
    dynarray* res = per_get_ancestor(child2 ,NULL); //haetaan kaikki esivanhemmat
    
    bool p1_found =false, p2_found=false, p3_found = false;
    for (unsigned int i = 0; i < res->top; ++i){
        person* tmp = (person*) da_get(res,i);
        if (per_compare(tmp,parent1) == 0) p1_found = true;
        if (per_compare(tmp,parent2) == 0) p2_found = true;
        if (per_compare(tmp,child) == 0) p3_found = true;
    }
    
    CU_ASSERT(p1_found);
    CU_ASSERT(p2_found);
    CU_ASSERT(p3_found);
    da_free(res);
}

void testPer_get_children() {
     person* parent1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* parent2 = ft_get_person_by_name(L"Vielä Yksi");
    
    wchar_t* name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Lapsi 5");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2340),L'm');
    
    person* child = ft_get_person_by_name(L"Lapsi 5");
    
    bool result = per_add_child(parent1,parent2,child);
    
    CU_ASSERT(result);
    
    name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Lapsi 6");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2340),L'm');
    
    person* child2 = ft_get_person_by_name(L"Lapsi 6");
    
    result = per_add_child_singleparent(parent1,child2);
    CU_ASSERT(result);
    
    
    
    dynarray* res = per_get_children(parent1);
    
    bool child_found =false,  child2_found = false;
    
    for (unsigned int i = 0; i < res->top; ++i){
        person* tmp = (person*) da_get(res,i);
        if (per_compare(tmp,child) == 0) child_found = true;
        if (per_compare(tmp,child2) == 0) child2_found = true;
    }
    
    da_free( res);
    CU_ASSERT(child_found);
    CU_ASSERT(child2_found);
    
         res = per_get_children(parent2);
    
    child_found = false;
    child2_found = false;
    
    for (unsigned int i = 0; i < res->top; ++i){
        person* tmp = (person*) da_get(res,i);
        if (per_compare(tmp,child) == 0) child_found = true;
        if (per_compare(tmp,child2) == 0) child2_found = true;
    }
    da_free(res);
    
    CU_ASSERT(child_found);
    CU_ASSERT(!child2_found);
}

void testPer_get_offspring() {
    person* parent1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* parent2 = ft_get_person_by_name(L"Vielä Yksi");
    
    wchar_t* name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Lapsi 7");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2340),L'm');
    
    person* child = ft_get_person_by_name(L"Lapsi 7");
    
    bool result = per_add_child(parent1,parent2,child);
    
    CU_ASSERT(result);
    
    
    name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Lapsi 8");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2345),L'm');
    
    person* child2 = ft_get_person_by_name(L"Lapsi 8");
    
    result = per_add_child_singleparent(child,child2);
    CU_ASSERT(result);
    
    
    
    dynarray* res = per_get_offspring(parent1, NULL);
    
    bool child_found =false,  child2_found = false;
    
    for (unsigned int i = 0; i < res->top; ++i){
        person* tmp = (person*) da_get(res,i);
        if (per_compare(tmp,child) == 0) child_found = true;
        if (per_compare(tmp,child2) == 0) child2_found = true;
    }
    
    da_free( res);
    CU_ASSERT(child_found);
    CU_ASSERT(child2_found);
}

void testPer_get_other_rel() {
    person* person1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* person2 = ft_get_person_by_name(L"Vielä Yksi");
    
    CU_ASSERT(per_add_relation(person1,person2,REL_OTHER));
    
    dynarray* result = per_get_other_rel(person1);
    
    bool person_found =false;
    
    for (unsigned int i = 0; i < result->top; ++i){
        person* tmp = (person*) da_get(result,i);
        if (per_compare(tmp,person2) == 0) person_found = true;
    }
    
    da_free( result);
    CU_ASSERT(person_found);
    
    result = per_get_other_rel(person2);
    
    person_found =false;
    
    for (unsigned int i = 0; i < result->top; ++i){
        person* tmp = (person*) da_get(result,i);
        if (per_compare(tmp,person1) == 0) person_found = true;
    }
    
    da_free( result);
    CU_ASSERT(person_found);
    
}

void testPer_get_parents() {
    person* parent1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* parent2 = ft_get_person_by_name(L"Vielä Yksi");
    
    wchar_t* name = malloc(40*sizeof(wchar_t));
    wcscpy(name,L"Lapsi 9");
    ft_add_person(name,new_date(5,2,2322),new_date(4,8,2346),L'm');
    
    person* child = ft_get_person_by_name(L"Lapsi 9");
    
    CU_ASSERT(per_add_child(parent1,parent2,child));
    
    
    dynarray* result = per_get_parents(child);
    
    bool p1_found =false,p2_found = false;
    
    for (unsigned int i = 0; i < result->top; ++i){
        person* tmp = (person*) da_get(result,i);
        if (per_compare(tmp,parent1) == 0) p1_found = true;
        if (per_compare(tmp,parent2) == 0) p2_found = true;
    }
    
    da_free( result);
    CU_ASSERT(p1_found);
    CU_ASSERT(p2_found);
}

void testPer_get_partner() {
    person* person1 = ft_get_person_by_name(L"Toinen Henkilö");
    person* person2 = ft_get_person_by_name(L"Testi Äöä");
    
    CU_ASSERT(per_add_relation(person1,person2,REL_MARRIAGE));
    
    dynarray* result = per_get_partner(person1);
    
    bool person_found =false;
    
    for (unsigned int i = 0; i < result->top; ++i){
        person* tmp = (person*) da_get(result,i);
        if (per_compare(tmp,person2) == 0) person_found = true;
    }
    
    da_free( result);
    CU_ASSERT(person_found);
    
    result = per_get_partner(person2);
    
    person_found =false;
    
    for (unsigned int i = 0; i < result->top; ++i){
        person* tmp = (person*) da_get(result,i);
        if (per_compare(tmp,person1) == 0) person_found = true;
    }
    
    da_free( result);
    CU_ASSERT(person_found);
}

void testPer_has_relation() {
   person* person1 = ft_get_person_by_name(L"Vielä Yksi");
    person* person2 = ft_get_person_by_name(L"Testi Äöä");
    
    CU_ASSERT(per_add_relation(person1,person2,REL_MARRIAGE));
    
    relation r;
    r.person1 =person1;
    r.person2 = person2;
    r.type =REL_MARRIAGE;
    
    CU_ASSERT(per_has_relation(person1,&r));
    CU_ASSERT(per_has_relation(person2,&r));
    
}

void testPer_remove_relation() {
    person* person1 = ft_get_person_by_name(L"Vielä Yksi");
    person* person2 = ft_get_person_by_name(L"Testi Äöä");
    
    CU_ASSERT(per_add_relation(person1,person2,REL_OTHER));
    
    relation r;
    r.person1 =person1;
    r.person2 = person2;
    r.type =REL_OTHER;
    
    CU_ASSERT(per_has_relation(person1,&r));
    CU_ASSERT(per_has_relation(person2,&r));
    
    CU_ASSERT(per_remove_relation(&r));
    
    CU_ASSERT(!per_has_relation(person1,&r));
    CU_ASSERT(!per_has_relation(person2,&r));
}

void testPer_set_birthday() {
    person* person1 = ft_get_person_by_name(L"Vielä Yksi");
    
    date tmp = new_date(6,2,3432);
    CU_ASSERT(date_compare(&tmp, &(person1->birthdate)) == 0);
    per_set_birthday(person1, new_date(1,1,1));
    tmp = new_date(1,1,1);
    CU_ASSERT(date_compare(&tmp,&(person1->birthdate))== 0);
}

void testPer_set_deathday() {
    person* person1 = ft_get_person_by_name(L"Vielä Yksi");
    
    date tmp = new_date(4,5,6252);
    CU_ASSERT(date_compare(&tmp, &(person1->deathdate)) == 0);
    per_set_deathday(person1, new_date(1,1,1));
    tmp = new_date(1,1,1);
    CU_ASSERT(date_compare(&tmp,&(person1->deathdate))== 0);
}

int main() {
    CU_pSuite pSuite = NULL;

    /* Initialize the CUnit test registry */
    if (CUE_SUCCESS != CU_initialize_registry())
        return CU_get_error();

    /* Add a suite to the registry */
    pSuite = CU_add_suite("persontest", init_suite, clean_suite);
    if (NULL == pSuite) {
        CU_cleanup_registry();
        return CU_get_error();
    }

    /* Add the tests to the suite */
    if ((NULL == CU_add_test(pSuite, "testPer_add_child", testPer_add_child)) ||
            (NULL == CU_add_test(pSuite, "testPer_add_child_singleparent", testPer_add_child_singleparent)) ||
            (NULL == CU_add_test(pSuite, "testPer_compare", testPer_compare)) ||
            (NULL == CU_add_test(pSuite, "testPer_get_ancestor", testPer_get_ancestor)) ||
            (NULL == CU_add_test(pSuite, "testPer_get_children", testPer_get_children)) ||
            (NULL == CU_add_test(pSuite, "testPer_get_offspring", testPer_get_offspring)) ||
            (NULL == CU_add_test(pSuite, "testPer_get_other_rel", testPer_get_other_rel)) ||
            (NULL == CU_add_test(pSuite, "testPer_get_parents", testPer_get_parents)) ||
            (NULL == CU_add_test(pSuite, "testPer_get_partner", testPer_get_partner)) ||
            (NULL == CU_add_test(pSuite, "testPer_has_relation", testPer_has_relation)) ||
            (NULL == CU_add_test(pSuite, "testPer_remove_relation", testPer_remove_relation)) ||
            (NULL == CU_add_test(pSuite, "testPer_set_birthday", testPer_set_birthday)) ||
            (NULL == CU_add_test(pSuite, "testPer_set_deathday", testPer_set_deathday))) {
        CU_cleanup_registry();
        return CU_get_error();
    }

    /* Run all tests using the CUnit Basic interface */
    printf("persontest.c:");
    CU_basic_set_mode(CU_BRM_VERBOSE);
    CU_basic_run_tests();
    CU_cleanup_registry();
    return CU_get_error();
}
